#include "myfile.h"

MY_FILE* myfopen(const char* path,const char* mode)
{
    assert(path);
    assert(mode);

    //调用系统接口，打开文件
    int flag = 0;
    if(strcmp(mode,"w")==0) flag = O_WRONLY|O_CREAT|O_TRUNC;
    else if(strcmp(mode,"r")==0) flag = O_RDONLY;
    else if(strcmp(mode,"a")==0) flag = O_WRONLY|O_CREAT|O_APPEND;
    else return NULL;

    //尝试打开文件
    int fd = 0;
    if(flag & O_CREAT) fd = open(path,flag,0666);
    else fd = open(path,flag);
    
    if(fd < 0)
    {
        return NULL;
    }

    //开辟一个MY_FILE结构体
    MY_FILE* mf = (MY_FILE*)malloc(sizeof(MY_FILE));
    if(mf==NULL)
    {
        perror("malloc fail");
        return NULL;
    }
   
    //对MY_FILE结构体初始化
    mf->_fileno = fd;
    mf->_flag = flag;
    //刷新策略要根据文件属性判断
    //这里简单认为每个文件都是行刷新|全刷新
    mf->_ft = LINE_FLUSH | ALL_FLUSH;
    memset(mf->outbuf,0,NUM);

    return mf;
}

int myfclose(MY_FILE* fp)
{
    assert(fp);
    //若此时MY_FILE缓冲区中还有数据，会自动刷新到文件缓冲区
    myfflush(fp);
    int ret = close(fp->_fileno);
    free(fp);
    fp=NULL;

    return ret; 
}


size_t myfwrite(const void *ptr, size_t size, size_t nmemb, MY_FILE *stream)
{
    assert(ptr);
    assert(stream);

    if(stream->_flag & O_RDONLY)
    {
        exit(1);
    }

    //先将数据写入MY_FILE的缓冲区中
    //若缓冲区剩余空间足够，则直接写入
    //若缓冲区剩余空间不足，则只能写入剩余空间
    
    int n = size*nmemb;//拷贝n个字节
    int remain_size = sizeof(stream->outbuf)-stream->_outcur;
    int valid_size = 0;
    if(remain_size >= n) 
    {
        memcpy(stream->outbuf+stream->_outcur, (char*)ptr, n);
        valid_size = n;
    }
    else
    {
        memcpy(stream->outbuf+stream->_outcur,(char*)ptr,remain_size);
        valid_size = remain_size;
    }
    stream->_outcur += valid_size;


    //刷新策略
    if(stream->_ft == NONE_FLUSH)
    {
        myfflush(stream);
    }
    else if(stream->_ft & LINE_FLUSH)
    {
        if(stream->outbuf[stream->_outcur-1]=='\n')
        {
            myfflush(stream);
        }
    }
    else if(stream->_ft & ALL_FLUSH)
    {
        if(stream->_outcur == sizeof(stream->outbuf))
        {
            myfflush(stream);
        }
    }

    //返回加入缓冲区中的有效字节个数
    return valid_size;
}

int myfflush(MY_FILE* fp)
{
    assert(fp);
    //将MY_FILE缓冲区的数据冲刷到文件对象缓冲区（系统级）上
    int ret = write(fp->_fileno,fp->outbuf,fp->_outcur);
    fp->_outcur = 0;
    sync();
    return ret;
}
